home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #2
/
Monster Media No. 2 (Monster Media)(1994).ISO
/
utils1
/
2m21src.zip
/
2MFBOOT.ASM
< prev
next >
Wrap
Assembly Source File
|
1994-05-31
|
64KB
|
1,492 lines
;┌───────────────────────────────────────────────────────────────────┐
;│ │
;│ █████ █ █ █▀▀▀▀ █▀▀▄ ▄▀▀▀▄ ▄▀▀▀▄ ▀▀█▀▀ │
;│ █ ██ ██ █ █ █ █ █ █ █ █ │
;│ █████ █ █ █ █▀▀ █▀▀█ █ █ █ █ █ │
;│ █ █ █ █ █ █ █ █ █ █ █ │
;│ █████ █ █ █ █▄▄▀ ▀▄▄▄▀ ▀▄▄▄▀ █ │
;│ │
;│ 2MFBOOT 2.1 - (C) Mayo 1994 Ciriaco García de Celis. │
;│ │
;│ CODIGO 2M PARA ARRANQUE FRIO DESDE DISQUETE. │
;│ │
;│ Proceso: │
;│ │
;│ TASM 2MFBOOT /m5 │
;│ TLINK 2MFBOOT │
;│ EXE2BIN 2MFBOOT.EXE 2MFBOOT.BIN │
;│ │
;│ El fichero .BIN hay que convertirlo a .DB con 2MFBMAKE.BAS │
;│ Es necesario que este fichero ocupe exactamente 2560 bytes │
;│ │
;└───────────────────────────────────────────────────────────────────┘
.286 ; versión para AT o superior
; ------------ Macros de propósito general.
XPUSH MACRO regmem ; apilar lista de registros
IRP rm, <regmem>
PUSH rm
ENDM
ENDM
XPOP MACRO regmem ; desapilar lista de registros
IRP rm, <regmem>
POP rm
ENDM
ENDM
DELAY MACRO ; estados de espera
JMP SHORT $+2 ; para AT obsoleto
JMP SHORT $+2
ENDM
PMICRO MACRO
CALL pmicro_iter ; realmente es una subrutina
ENDM
; ------------ Estructura de datos con información para cada unidad.
info_drv STRUC
maxs EQU 13 ; máximo 13 sectores físicos/pista
tipo_drv DB ? ; tipo de la disquetera (0 = no hay)
control2m_flag DB OFF ; a ON si 2M controla la unidad
cambio DB ON ; a ON indica cambio de soporte
version_fmt DB ? ; versión del formato de disco 2M
multi_io DB ? ; a 0 si posible acceso multi-sector
chk DB ? ; a 0 si checksum del sector 0 Ok
vunidad EQU THIS WORD
vunidad0 DB ? ; velocidad pista 0
vunidadx DB ? ; velocidad demás pistas
gap DB ? ; GAP entre sectores (leer/escribir)
sectpista DB ? ; sectores lógicos por pista
tabla_tsect DB maxs DUP (?) ; tamaños de sectores 1, 2, ..., N
tam_fat DB ? ; sectores/FAT en la unidad
ENDS
; ------------ Programa.
_PRINCIPAL SEGMENT
ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
ORG 0 ; código binario puro
; ****************************************
; * *
; * D A T O S R E S I D E N T E S *
; * *
; ****************************************
; ------------ Variables del programa (justo al principio).
info_ptr DW info_A ; punteros a datos de las unidades
DW info_B
DB "21" ; Versión 2MFBOOT 2.1
id_sistema DB "2M-STV" ; identificación de disco 2M
unidad DB ? ; unidad física de disco en curso
numsect DW ? ; sectores a transferir
sectini DW ? ; primer sector DOS a transferir
cilindro DB ? ; cilindro del disco a acceder
cabezal DB ? ; cabezal a emplear
sector DB ? ; número de sector físico
sector_ini DB ? ; número de sector físico inicial
sector_fin DB ? ; número de sector físico final
seccion DB ? ; parte del sector físico en curso
secciones DB ? ; sectores lógicos a transferir
tsector DB ? ; LOG2 (tamaño de sector) - 7
buffer DW buffer_io ; puntero al buffer intermedio
buf_unidad DB ? ; unidad del sector en el buffer
buf_cilcab DW ? ; cilindro/cabezal de sector buffer
buf_sector DB ? ; número de sector en el buffer
status DB ? ; resultado de los accesos a disco
fdc_result DB 7 DUP (?) ; bytes de resultados del FDC
orden DB ? ; operación F_READ/F_WRITE/F_VERIFY
tab_ordenes DB F_READ
DB F_WRITE
DB F_VERIFY ; órdenes 2, 3 y 4
; --- Interpretación BIOS de los bits de ST1
lista_errs DB 4 ; 'sector not found'
DB 0
DB 10h ; 'bad CRC'
DB 8 ; 'DMA overrun'
DB 0
DB 4 ; 'sector not found'
DB 3 ; 'write-protect error'
DB 2 ; 'address mark not found'
DB 20h ; en otro caso: 'bad NEC'
info_A info_drv <> ; datos de A:
info_B info_drv <> ; datos de B:
; ***************************************
; * *
; * C O D I G O R E S I D E N T E *
; * *
; ***************************************
; ------------ Nueva rutina de gestión de INT 13h. Llama a la INT 13h
; original o a una nueva rutina de control para la
; lectura (AH=2), escritura (AH=3) y verificación (AH=4)
; según el tipo de disco introducido.
ges_int13 PROC FAR
STI
CLD
PUSHF
PUSH SI
CMP DL,2
JAE ges13bios ; no es disquetera A: ó B:
CALL set_SI_drv
CMP CS:[SI].tipo_drv,2 ; ¿unidad 1.2M?
JE ges_2m
CMP CS:[SI].tipo_drv,4 ; ¿unidad 1.44/2.88M?
ges_2m: JC ges13bios ; no es unidad de alta densidad
CMP AH,2
JB ges13bios ; no Read/Write/Verify/Format
CMP AH,5
JA ges13bios ; no Read/Write/Verify/Format
JNE no_format
CALL set_flag_STV ; CF = 0 -> "disco no 2M"
JMP ges13bios
no_format: CALL detecta_cambio ; ¿cambio de disco?
JNC dilucida
POP SI
POPF
STC ; hubo cambio:
MOV AX,600h
RET 2 ; retornar con error
dilucida: CMP CS:[SI].control2m_flag,OFF
JE ges13bios ; la unidad la controla la BIOS
POP SI
POPF
CALL control2m ; la controla 2M
RET 2
ges13bios: POP SI
POPF
JMP CS:ant_int13 ; saltar al gestor de INT 13h
ges_int13 ENDP
; ------------ A la entrada en DL se indica la unidad y a la salida se
; devuelve SI apuntando sus variables sin alterar flags.
set_SI_drv PROC
PUSHF
PUSH BX
MOV BL,DL
MOV BH,0
SHL BX,1
MOV SI,CS:[BX+OFFSET info_ptr]
POP BX
POPF
RET
set_SI_drv ENDP
; ------------ Si CF=1, indicar disquete 2M presente. A la
; entrada, DL indica la unidad de disco.
set_flag_STV PROC
PUSHA
CALL set_SI_drv
MOV AL,ON ; indicar 2M
JC tipo_stv_ok
MOV AL,OFF ; indicar no 2M
tipo_stv_ok: MOV CS:[SI].control2m_flag,AL
POPA
RET
set_flag_STV ENDP
; ------------ Devolver ZF=1 si cilindro y cabezal 0.
pista0? PROC
PUSH AX
MOV AL,cabezal
OR AL,cilindro
POP AX
RET
pista0? ENDP
; ------------ Devolver ZF=1 si la línea de cambio de disco está
; inactiva. A la entrada, DL contiene la unidad. El
; motor es puesto en marcha y, si no lo estaba ya, la
; variable que indica lo que resta para detenerlo
; es llevada a su valor normal, por lo que el disco no
; tardará mucho en detenerse (incluso sin quizá haber
; acelerado aún). En la práctica, invocando esta rutina
; desde INT 13h nunca será necesario arrancar el motor
; ya que el DOS ejecuta antes la función equivalente,
; la 16h, que lo pone en marcha. Es simplemente una
; medida de seguridad contra las BIOS «de marca».
leer_lin_camb PROC
PUSHA ; *
PUSH DS
PUSH 40h
POP DS
MOV AL,1
MOV CL,DL
SHL AL,CL ; bit de motor en 0..3
TEST DS:[3Fh],AL
JNZ rodando ; el motor ya está girando
CLC
CALL motor_off_cnt ; cuenta normal detención motor
rodando: MOV AH,DL
SHL AH,4
OR AH,AL ; AH = byte BIOS
SHL AL,4
OR AL,00001100b ; modo DMA, no hacer reset
OR AL,DL ; AL para reg. salida digital
MOV DX,3F2h
CLI
MOV DS:[3Fh],AH ; actualizar variable BIOS
OUT DX,AL ; arrancado motor en la unidad
ADD DX,5
DELAY
IN AL,DX ; leer línea de cambio de disco
STI
TEST AL,80h ; ZF=0 -> cambio de disco
POP DS
POPA ; *
RET
leer_lin_camb ENDP
; ------------ Determinar si ha habido cambio de disco y, en ese caso,
; si el nuevo disquete es de tipo 2M o no. El cambio de
; disco se detecta leyendo la línea de cambio de disco o
; chequeando la variable que indica si ha habido cambio
; o no (esta variable está a ON tras instalar 2M para
; forzar la detección del tipo de disco introducido; se
; pone en ON también si no se logra bajar la línea de
; cambio de disco por si fuera un soporte raro y la BIOS
; sí lo lograra -forzando así una detección posterior-).
detecta_cambio PROC
PUSHA ; *
CALL set_SI_drv ; SI -> variables de la unidad
CMP CS:[SI].cambio,ON ; ¿cambio de soporte?
MOV CS:[SI].cambio,OFF
JE hubo_cambio
CALL leer_lin_camb ; leer línea de cambio de disco
JNZ hubo_cambio
POPA
CLC ; no hay cambio de disco
RET
hubo_cambio: CLC
CALL set_flag_STV ; CF = 0 -> supuesto no 2M
XPUSH <DS, ES> ; **
MOV BX,90h
ADD BL,DL
PUSH 40h
POP DS
AND BYTE PTR [BX],255-16 ; densidad no determinada
XPUSH <CS, CS>
XPOP <DS, ES>
MOV unidad,DL
STC ; asegurar motor en marcha
CALL reset_drv
MOV cilindro,1
MOV cabezal,0
CALL seek_drv ; bajar línea cambio de disco
DEC cilindro
CALL seek_drv
CLC
CALL motor_off_cnt ; cuenta normal detención motor
CALL leer_lin_camb ; ¿bajada línea cambio disco?
JZ disco_dentro ; se pudo: hay disco dentro
MOV [SI].cambio,ON ; futura detección tipo disco
CLC ; NO indicar cambio de disco...
JMP fin_detecta ; ...para pasar control a BIOS
disco_dentro: PUSH DS
PUSH 40h
POP DS
MOV BYTE PTR DS:[41h],6 ; error 'media changed'
POP DS
MOV buf_unidad,-1 ; invalidar buffer
MOV [SI].gap,20 ; GAP provisional
MOV CX,3 ; 3 intentos
intenta_io0: PUSH CX
CMP CX,2 ; CF=1 la 3ª vez (a 0 si CX<>1)
CALL reset_drv
MOV [SI].vunidad0,0 ; empezar con 500 Kbit/seg.
intenta_io: MOV cilindro,0
MOV cabezal,0
MOV sector,1 ; sector de arranque
MOV seccion,0
MOV secciones,1
MOV orden,F_READ
MOV DI,buffer
CALL direct_acceso
JNE otra_densidad ; es otra densidad de disco
POP CX
MOV BX,buffer
CALL set_info ; características nuevo soporte
CLC
JMP fin_detecta_c ; indicar cambio de disco
otra_densidad: MOV AL,[SI].vunidad0
INC AX ; próxima velocidad
CMP AL,3
JA otro_intento
MOV [SI].vunidad0,AL
JMP intenta_io ; probar otra velocidad
otro_intento: MOV [SI].vunidad0,0
POP CX
LOOP intenta_io0 ; reintento
fin_detecta_c: STC ; indicar cambio de disco
fin_detecta: XPOP <ES, DS> ; **
POPA ; *
RET
detecta_cambio ENDP
; ------------ Anotar la información del disquete si es de tipo 2M.
; A la entrada, DS:SI apunta a las variables de la unidad
; y ES:BX al sector de arranque del disco. Se actualiza
; también la variable BIOS de tipo de densidad (la BIOS
; no se da cuenta del cambio de disco y conviene ayudar).
set_info PROC
PUSHA
CALL calc_chk
JC set_info_exit ; no es disco 2M
MOV [SI].chk,AL ; anotar checksum
MOV [SI].version_fmt,CL ; y versión del formato
MOV DL,unidad
STC
CALL set_flag_STV ; CF = 1 -> indicar disco 2M
MOV AL,ES:[BX+22] ; tamaño de FAT
MOV [SI].tam_fat,AL
MOV CL,ES:[BX+65] ; CL a 0 si acceso multi-sector
MOV [SI].multi_io,CL
MOV AX,ES:[BX+66]
MOV [SI].vunidad,AX ; velocidad pista 0 / demás
MOV AL,ES:[BX+24]
MOV [SI].sectpista,AL ; sectores/pista
MOV DI,ES:[BX+72]
MOV AL,ES:[BX+DI+1] ; GAP de formateo
MOV AH,AL
AND CL,CL ; CL a 0 si acceso multi-sector
JZ gap_rw_ok ; GAP R/W para /F
ADD AH,190
MOV AL,11
MUL AH ; AX = (190+GAP)*11
SUB AX,2048+62
gap_rw_ok: SHR AL,1 ; GAP R/W para /M
MOV [SI].gap,AL
MOV CX,maxs
MOV DI,ES:[BX+74]
ADD DI,BX
LEA BX,[SI].tabla_tsect
genera_ts: MOV AL,ES:[DI]
MOV [BX],AL
INC BX
INC DI
LOOP genera_ts ; información estructura pistas
set_info_exit: MOV AL,[SI].vunidad0
SHL AL,6 ; velocidad en bits 7:6
OR AL,00010111b ; establecido otro medio físico
CMP [SI].tipo_drv,2
JA modo_ok ; es unidad de 3½
AND AL,11111000b
OR AL,00000101b ; 1.2 en 1.2
TEST AL,01000000b
JZ modo_ok
XOR AL,00100001b ; 360 en 1.2 y seek * 2
modo_ok: PUSH DS
MOV BX,90h
ADD BL,unidad
PUSH 40h
POP DS
AND BYTE PTR DS:[BX],8 ; respetar bit de 2.88M
OR DS:[BX],AL ; actualizar variable BIOS
POP DS ; con el tipo de densidad
POPA
RET
set_info ENDP
; ------------ Calcular el checksum de la zona vital del sector de
; arranque. A la entrada, ES:BX -> sector de arranque.
; A la salida, CF=1 si el disco no es 2M; de otro modo
; checksum en AL y versión del formato de disco en CL.
calc_chk PROC
XPUSH <SI, DI>
LEA DI,[BX+3] ; DI=BX+3
LEA SI,id_sistema
MOV CX,6
REP CMPSB ; comparar identificación
STC
JNE chk_ret ; el disco no es 2M
XOR AX,AX
MOV CL,ES:[BX+64] ; versión del formateador
CMP CL,6
JB chk_ok ; no usaba este checksum
MOV DI,ES:[BX+68]
chk_sum: DEC DI
ADD AL,ES:[BX+DI]
CMP DI,63
JA chk_sum
chk_ok: CLC
chk_ret: XPOP <DI, SI>
RET
calc_chk ENDP
; ------------ Determinar el tipo de error producido en el acceso.
set_err PROC
PUSHA
JNC err_ret ; no hay error
CMP status,0 ; ¿'status' ya asignado?
JNE err_retc ; no cambiarlo si es así
MOV AL,BYTE PTR fdc_result+1
AND AL,10110111b ; aislar condiciones de test
LEA BX,lista_errs
MOV CX,9
busca_err: MOV AH,[BX] ; código de error BIOS
SHL AL,1
JC err_ok ; es ese error
INC BX
LOOP busca_err ; buscar otro error
err_ok: OR status,AH
err_retc: STC ; condición de error
err_ret: POPA
RET
set_err ENDP
; ------------ Actualizar variables de error de la BIOS.
set_bios_err PROC
PUSHF ; *
PUSHA ; **
PUSH ES ; ***
PUSH 40h
POP ES
MOV DI,41h ; bytes de resultados del 765
LEA SI,status ; variable BIOS de status y 7
MOV CX,4 ; bytes: 4 palabras
REP MOVSW
POP ES ; ***
POPA ; **
POPF ; *
RET
set_bios_err ENDP
; ------------ Realizar lecturas, escrituras y verificaciones: rutina
; que sustituye el código de la BIOS para poder soportar
; los formatos 2M. La operación puede quedar dividida en
; tres fases: el fragmento anterior a la FAT2, la zona
; correspondiente a la FAT2 (se ignora la escritura y se
; simula su lectura leyendo la FAT1) y un último bloque
; ubicado tras la FAT2. El sector de arranque es emulado
; empleando el primer sector físico de la FAT2 (aunque en
; los discos de versión de formato anterior a la 7 se usa
; el sector de arranque verdadero -permitiendo escribirlo
; sólo si es válido-). En cualquier caso, si el número de
; cabezal tiene el bit 7 activo, se sobreentiende que el
; programa que llama soporta disquetes 2M y no se emula
; la FAT2 ni el sector de arranque, para permitirle
; acceder al código SuperBOOT. Las coordenadas de la BIOS
; se traducen a las unidades del DOS por mayor comodidad.
control2m PROC
PUSH DS ; *
PUSHA ; **
PUSH CS
POP DS
MOV unidad,DL
CALL set_SI_drv ; SI -> variables de la unidad
CMP [SI].chk,0
JE chk_valido ; checksum correcto en sector 0
MOV status,40h ; devolver 'Seek Error' al DOS
JMP exit_2m_ctrl
chk_valido: PUSH AX ; ***
MOV AH,0
MOV numsect,AX ; nº sectores
MOV AL,CH ; cilindro
SHL AL,1
MOV DL,DH
AND DH,01111111b
ADD AL,DH ; cabezal físico
MUL [SI].sectpista
ADD AL,CL ; sector
ADC AH,0
DEC AX ; AX = nº sector DOS
MOV sectini,AX
MOV DI,BX ; ES:DI -> dirección
POP BX ; ***
MOV BL,BH
MOV BH,0
MOV CL,[BX+OFFSET tab_ordenes-2]
MOV orden,CL
SHL DL,1
JC acceso_final ; cabezal >= 128: no emular
AND AX,AX ; ¿comienza en sector 0?
JNZ io_emula ; no
CMP [SI].version_fmt,7
JB boot_real ; no soportado BOOT virtual
MOV AL,[SI].tam_fat ; AH = 0
INC AX
MOV CX,1 ; sector BOOT emulado en
CALL ejecuta_io ; el primer sector FAT2
JNE fin_ctrl
boot_fin_op: DEC numsect
INC sectini
MOV AX,sectini
JMP io_emula
boot_real: CMP orden,F_WRITE
JNE io_emula
MOV BX,DI ; BOOT de 2M 1.3 y anteriores
CALL calc_chk
JC si_skip ; no es de tipo 2M
AND AL,AL
JZ io_emula ; lo es y con checksum correcto
si_skip: ADD DI,512
JMP boot_fin_op ; impedir estropicio de BOOT
io_emula: MOV CL,[SI].tam_fat
MOV CH,0 ; CX = primer sector FAT2 - 1
CMP AX,CX
JA en_fat2? ; ¿la operación afecta a FAT2?
CALL calc_iop ; calcular sectores antes FAT2
CALL ejecuta_io ; CX sectores desde AX
JNE fin_ctrl ; error
CMP numsect,0
JE fin_ctrl ; fin de la transferencia
en_fat2?: MOV AX,sectini
MOV CL,[SI].tam_fat
MOV CH,0
SHL CX,1 ; CX = último sector FAT2
CMP AX,CX
JA acceso_final ; la operación es tras la FAT2
CALL calc_iop ; sectores hasta fin de FAT2
CMP orden,F_WRITE
JNE emula_fat1
SHL CX,9 ; CX = CX * 512
ADD DI,CX ; ES:DI actualizado
JMP acceso_final
emula_fat1: MOV DL,[SI].tam_fat
MOV DH,0
SUB AX,DX ; leer de FAT1 y no de la FAT2
CALL ejecuta_io ; CX sectores desde AX
JNE fin_ctrl ; error
acceso_final: CMP numsect,0
JE fin_ctrl ; fin de la transferencia
MOV AX,sectini
MOV CX,numsect
CALL ejecuta_io
fin_ctrl: CLC
CALL motor_off_cnt ; cuenta normal detención motor
CALL set_bios_err ; actualizar variables BIOS
exit_2m_ctrl: POPA ; **
MOV AH,status
POP DS ; *
AND AH,AH
JZ st_ok ; resultado correcto (CF=0)
STC ; error
MOV AL,0 ; 0 sectores movidos
st_ok: RET
calc_iop: SUB CX,AX
INC CX ; CX sectores
CMP CX,numsect
JBE nsect_ok
MOV CX,numsect ; sólo quedan CX
nsect_ok: SUB numsect,CX
ADD sectini,CX
RET
control2m ENDP
; ------------ A la entrada, AX indica el sector inicial (coordenadas
; del DOS) y CX el número de sectores a procesar.
; * Definiciones: «Sector físico» es un sector del disco
; de 512, 1024 ó 2048 bytes (números de sector del 1 al N
; en la pista). Este sector físico está dividido en
; «secciones» de 512 bytes, constando por tanto de 1, 2 ó
; 4 secciones. «Sector virtual» es el número de sector
; del programa que llama a INT 13h, comprendido entre 1 y
; M. Esta estructura de N sectores por pista de distintos
; tamaños, se verifica en todo el disco con excepción del
; cabezal y cilindro 0 (con un formato más convencional
; de sectores de 512 bytes numerados de 1 a J, aunque no
; existen algunos de los intermedios que corresponden a
; la segunda copia de la FAT).
; * Primero se convierte el sector virtual (1..M) en su
; correspondiente físico (1..J en la pista 0 y 1..N en
; las demás), deduciendo qué porción de 512 bytes (o
; sección) es afectada. Un sector virtual (512 bytes)
; simulado suele ser parte de un sector físico de 2048
; bytes en muchos casos. Si dicho sector físico ya había
; sido leído al buffer en anteriores accesos, se extrae
; la sección necesaria. Si no, se carga del disco y se
; extrae dicho fragmento. El número de sectores virtuales
; que se solicitan (=secciones) permite realizar un bucle
; hasta completar la transferencia; el interleave 1:2 de
; los sectores físicos en /M permite acceder sector a
; sector sin pérdida de rendimiento. En el caso de la
; escritura, se estudia primero si hay varios sectores
; virtuales consecutivos que escribir, completando entre
; todos un sector físico: en ese caso, se prepara el
; mismo y se escribe sin más. En caso de que haya que
; modificar sólo una única sección de un sector físico,
; salvo si éste es de 512 bytes, no hay más remedio que
; cargarlo al buffer (realizar una prelectura),
; actualizar la sección correspondiente y volverlo a
; escribir.
; * En el formato /F se realiza una operación multisector
; si es posible y sin emplear el buffer intermedio (si
; bien podría ser preciso emplearlo con la primera y
; última sección); en los dos formatos de disco se hace
; la operación multisector en la primera pista. Las
; operaciones multisector puede que sea preciso
; dividirlas en tres fases: los sectores antes de una
; frontera de DMA, el que la cruza (que es transferido
; a través del buffer intermedio) y los que están detrás.
ejecuta_io PROC
MOV BX,AX ; AX = sector DOS inicial
MOV secciones,CL ; CX sectores (CL realmente)
DIV [SI].sectpista
INC AH ; numerado desde 1...
MOV sector,AH ; ...el resto es el sector
SHR AL,1
MOV cilindro,AL ; cilindro
RCL AL,1
AND AL,1
MOV cabezal,AL ; cabezal
MOV AL,sector
ADD AL,secciones
JC no_cabe ; sector+secciones > 255
DEC AX ; DEC AX = DEC AL
CMP AL,[SI].sectpista
JBE si_cabe
no_cabe: MOV status,4 ; 'sector no encontrado'
JMP fin_io
si_cabe: MOV AL,AH ; sector en AL
CBW ; sección 0 (AH = 0)
CALL pista0?
JZ s_xx ; sector físico en pista/cara 0
LEA BX,[SI].tabla_tsect-1
DEC AX ; AH = 0
resta_secc: INC BX
INC AH
MOV CL,[BX]
SUB CL,2
MOV CH,1
SHL CH,CL
SUB AL,CH
JNC resta_secc ; en las demás pistas
ADD AL,CH
XCHG AH,AL
s_xx: MOV sector,AL ; sector lógico convertido a
MOV seccion,AH ; sector y sección físicas
direct_acceso: CALL motor_ok ; asegurar que está en marcha
MOV AH,0
MOV sector_fin,AH ; no acceder a más de 1 sector
CALL pista0? ; (al menos de momento)
JNZ decide_multi ; no es pista 0
MOV AL,secciones
MOV secciones,AH ; las que restan (AH = 0)
JMP multi_proc
decide_multi: CMP [SI].multi_io,AH ; AH = 0
JNE io_pasos ; acceso sector a sector
CMP seccion,AH
JE multi_acc
CALL acceso_secc ; no acceso a inicio sector
JC fin_io
multi_acc: CMP secciones,AH ; AH = 0
JE fin_io
CALL num_secciones
MOV CL,AL
MOV AL,secciones ; AH = 0
DIV CL
AND AL,AL
JZ io_pasos ; no quedan sectores enteros
MOV secciones,AH ; las que restan
multi_proc: CALL acceso_multi ; de AL sectores
JC fin_io
io_pasos: CMP secciones,0
JE fin_io ; no restan secciones finales
CALL acceso_secc
JNC io_pasos
fin_io: CMP status,0 ; ZF = 1 -> operación correcta
RET
acceso_secc: PUSH AX
CMP orden,F_WRITE ; acabar transferencia sector
JE escritura
CMP orden,F_VERIFY
JE verificacion
CALL leido? ; realizar lectura...
JNC ya_leido ; sector ya en el buffer
hay_que_leer: CALL acceso_sector ; efectuar E/S
JC acc_ret ; ha habido fallo
ya_leido: CALL trans_secc ; buffer -> memoria
JMP acc_ret
escritura: CMP seccion,0
JNE prelectura ; sólo parte del sector cambia
CALL num_secciones
CMP secciones,AL
JAE escribir ; Todo el sector físico cambia
prelectura: CALL leido? ; Leer el sector físico para
JNC escribir ; cambiar sólo una parte de él
MOV orden,F_READ ; de momento leer...
CALL acceso_sector ; efectuar E/S
MOV orden,F_WRITE ; ... restaurar orden original
JC acc_ret ; ha habido fallo
escribir: CALL trans_secc ; memoria -> buffer
CALL acceso_sector ; volcar buffer al disco
JMP acc_ret
verificacion: PUSH BX
MOV BL,seccion
CALL num_secciones
dec_sec_veri: DEC secciones
JZ verifica
INC BX
CMP BL,AL
JB dec_sec_veri
verifica: POP BX
CALL acceso_sector ; leer para forzar verificación
acc_ret: PUSHF
INC sector ; preparado para otro sector
MOV seccion,0 ; desde su primera sección
POPF
POP AX
RET
acceso_multi: PUSH AX ; AL = sectores a transferir
AND AL,AL
JZ acc_mult_fin
MOV AH,sector
MOV sector_ini,AH
ADD AL,AH
DEC AX
MOV sector_fin,AL
INC AL
CALL acceso_sector ; sectores no problemáticos
MOV sector,AL
acc_mult_fin: POP AX
RET
ejecuta_io ENDP
; ------------ Mover secciones desde el buffer hacia la memoria (con
; orden F_READ) después de la lectura o de la memoria al
; buffer (orden F_WRITE) antes de la escritura. En la
; verificación (orden F_VERIFY) no se mueve nada porque
; esta subrutina no es invocada.
trans_secc PROC
XPUSH <AX, BX, CX, SI> ; *
MOV BL,seccion ; desde esta sección
CALL num_secciones ; nº secciones del sector
otra_secci: PUSH BX
SHL BX,9 ; sección * 512
ADD BX,buffer ; dirección
MOV SI,BX
MOV CX,256 ; tamaño sección (palabras)
CALL swap_reg ; ¿intercambiar origen-destino?
REP MOVSW ; copiar 512 bytes
CALL swap_reg ; ¿intercambiar origen-destino?
POP BX
DEC secciones ; una menos
JZ fin_secc
INC BX ; otra sección del sector
CMP BL,AL ; ¿sector agotado?
JB otra_secci ; aún no
fin_secc: XPOP <SI, CX, BX, AX> ; *
RET
swap_reg: CMP CS:orden,F_WRITE
JE interc
CLC
RET
interc: XCHG SI,DI ; en escritura, invertir el
XPUSH <ES, DS> ; sentido de la operación
XPOP <ES, DS>
RET
trans_secc ENDP
; ------------ Comprobar si el sector ya está en el buffer.
leido? PROC
PUSH AX
MOV AL,buf_unidad
CMP AL,unidad
JNE no_leido ; es en otra unidad
MOV AL,cilindro
MOV AH,cabezal
CMP AX,buf_cilcab
JNE no_leido ; es en otro cilindro/cabezal
MOV AL,buf_sector
CMP AL,sector
JNE no_leido ; es otro sector
POP AX
RET ; está en el buffer
no_leido: STC
POP AX
RET ; sector no leído
leido? ENDP
; ------------ Leer o escribir sector(es). Se selecciona el tamaño de
; sector correcto antes de llamar a sector_io. En esta
; rutina se actualiza la variable «status» en función de
; los posibles errores de acceso. Si sector_fin es
; distinto de 0 se accede a los sectores indicados, si es
; 0 se accede sólo al sector «sector» a través del buffer
; intermedio y al final se anota el sector cargado ó
; escrito para evitar futuras lecturas innecesarias, a
; modo de mini-caché que dispara la velocidad de acceso a
; sectores lógicos consecutivos.
acceso_sector PROC
XPUSH <AX, BX>
CALL seek_drv ; posicionar el cabezal
JNC en_pista
CMP status,0 ; ¿error ya determinado?
JNE acc_fin_err
OR status,40h ; no: pues 'seek error'
acc_fin_err: STC
JMP acceso_fin
en_pista: CALL pista0?
MOV AL,2
JZ tam_acc_ok ; sectores 512 en cil./cab. 0
LEA BX,[SI].tabla_tsect
ADD BL,sector
ADC BH,0
MOV AL,[BX-1]
tam_acc_ok: MOV tsector,AL
CMP sector_fin,0 ; ¿usar buffer intermedio?
JE acceso_buffer
CALL sector_io
MOV sector_fin,0 ; no acceder a más de 1 sector
PUSHF ; **1
JMP acceso_rep ; en el futuro (por defecto)
acceso_buffer: XPUSH <ES, DI>
PUSH CS
POP ES
MOV DI,buffer ; acceso con buffer auxiliar
MOV AL,sector ; mismo sector inicial/final
MOV sector_ini,AL
MOV sector_fin,AL
CALL sector_io
MOV sector_fin,0
XPOP <DI, ES>
PUSHF ; **2
MOV AL,-1 ; invalidar contenido buffer
JC acceso_anota ; si hay error
CMP orden,F_VERIFY
JE acceso_rep ; nada leído físicamente
MOV AL,unidad
acceso_anota: MOV buf_unidad,AL
MOV AL,cilindro
MOV AH,cabezal
MOV buf_cilcab,AX
MOV AL,sector
MOV buf_sector,AL ; anotado el sector en buffer
acceso_rep: POPF ; ** mucho cuidado con la pila
CALL set_err ; ajustar variable «status»
acceso_fin: XPOP <BX, AX>
RET
acceso_sector ENDP
; ------------ Devolver el número de secciones del sector en curso.
num_secciones PROC
CALL pista0?
MOV AL,1
JZ num_secc_ok ; sectores 512 en cil./cab. 0
XPUSH <BX, CX>
LEA BX,[SI].tabla_tsect
ADD BL,sector
ADC BH,0
MOV CL,[BX-1]
SUB CL,2
MOV AL,1
SHL AL,CL
XPOP <CX, BX>
num_secc_ok: RET ; resultado en AL
num_secciones ENDP
; ------------ Asegurar que el motor está en marcha.
motor_ok PROC
PUSHA ; *
PUSH DS ; **
MOV BX,40h
PUSH BX
POP DS
MOV CH,255-18 ; CH = 255 - 1 segundo
CLI
MOV CL,CS:unidad
MOV AL,1
SHL AL,CL
TEST [BX-1],AL ; ¿motor en marcha?
JZ arrancarlo ; arrancarlo
CMP [BX],CH ; Si encendido y acelerado...
JBE ok_motor ; ...seguir
arrancarlo: OR [BX-1],AL ; arrancar motor
AND BYTE PTR [BX-1],0CFh ; borrar número unidad
MOV AL,CL
SHL AL,4 ; unidad << 4
OR [BX-1],AL ; nuevo número de unidad
MOV BYTE PTR [BX],255 ; asegurar que no se pare
STI
MOV DX,3F2h ; registro de salida digital
ADD CL,4
MOV AL,1
SHL AL,CL ; colocar bit del motor
OR AL,CS:unidad ; seleccionar unidad
OR AL,00001100b ; modo DMA, no hacer reset
OUT DX,AL ; poner en marcha el motor
MOV AX,90FDh
CLC
INT 15h ; permitir multitarea
JC ok_motor ; timeout
MOV AX,1000 ; 1 segundo aceleración
CALL retardo ; esperar aceleración disco
ok_motor: MOV [BX],CH ; cuenta máxima detención motor
STI ; sin forzar futura aceleración
POP DS ; **
POPA ; *
RET
motor_ok ENDP
; ------------ Establecer modalidad de operación del controlador
; y poner el motor en marcha. Si CF=1 se le da tiempo
; además a la unidad para que acelere.
reset_drv PROC
PUSHA
CALL motor_off_cnt ; cuenta detención motor
MOV CL,unidad
MOV AL,CL
SHL AL,2 ; unidad seleccionada
OR AL,1 ; bit de motor
SHL AL,CL ; colocar dicho bit
PUSH DS ; *
PUSH 40h
POP DS
CLI
MOV DS:[3Fh],AL
AND BYTE PTR DS:[3Eh],70h ; bit IRQ=0 y recalibrar
POP DS ; *
SHL AL,4 ; bits motor en nibble alto
OR AL,CL ; seleccionar unidad
OR AL,00001000b ; interrupciones+DMA y reset
MOV DX,3F2h ; registro de salida digital
OUT DX,AL ; señal de reset
CALL fdc_respiro ; tiempo reconocer reset en 486
OR AL,00000100b
OUT DX,AL ; fin de señal de reset
CALL espera_int ; rehabilitará interrupciones
MOV AL,8
CALL fdc_write ; comando 'leer estado int...'
CALL fdc_read
CALL fdc_read
CALL envia_specify ; comando 'specify' adecuado
POPA
RET
reset_drv ENDP
; ------------ Enviar comando specify a la controladora. El step-rate
; se selecciona según la densidad, para evitar un sonido
; extraño al posicionar o recalibrar el cabezal.
envia_specify PROC
PUSH AX
PUSH DS
PUSH 40h
POP DS
MOV AH,DS:[8Bh]
POP DS
MOV AL,3 ; comando 'specify'
CALL fdc_write
MOV AL,0BFh ; step rate para 500 kbps
AND AH,11000000b
JZ spec1_ok
MOV AL,0AFh ; step rate para 1 Mbps
CMP AH,11000000b
JE spec1_ok
MOV AL,0DFh ; step rate para 250/300 Kbps
spec1_ok: CALL fdc_write
MOV AL,2
CALL fdc_write ; head load y modo DMA
POP AX
RET
envia_specify ENDP
; ------------ Recargar cuenta para la detención del motor. Si CF=1 al
; entrar, se establece la mayor cuenta posible; en caso
; contrario, se pone el valor normal de la tabla base.
motor_off_cnt PROC
PUSHA
PUSH DS
MOV AL,0FFh ; valor máximo
JC motor_off_ok
PUSH 0
POP DS
LDS BX,DWORD PTR DS:[1Eh*4] ; DS:BX -> INT 1Eh
MOV AL,[BX+2] ; byte 2 tabla base disco
motor_off_ok: PUSH 40h
POP DS
MOV BYTE PTR DS:[40h],AL ; cuenta parada motor
POP DS
POPA
RET
motor_off_cnt ENDP
; ------------ Llevar el cabezal a la pista indicada, recalibrando si
; hubo un reset (se invocó la función 0 de la INT 13h o
; se ejecutó reset_drv) antes de esta operación. Primero
; se selecciona la velocidad de transferencia y se borra
; el resultado de cualquier operación anterior, para que
; todo quede listo para el próximo acceso a disco.
seek_drv PROC
PUSHA
CALL set_rate ; velocidad / borrar resultados
CALL envia_specify ; comando 'specify' adecuado
MOV AH,1
MOV CL,unidad
SHL AH,CL ; AH = 1 (A:) ó 2 (B:)
PUSH DS
PUSH 40h
POP DS
TEST AH,DS:[3Eh]
POP DS
JNZ do_seek ; la unidad ya fue recalibrada
CALL recalibrar
JC fallo_seek ; fallo al recalibrar
do_seek: MOV BX,94h
ADD BL,unidad
MOV AL,cilindro
PUSH DS ; *
PUSH 40h
POP DS
OR DS:[3Eh],AH ; unidad ya recalibrada
MOV AH,DS:[41h] ; código de error previo
CMP AL,[BX]
MOV [BX],AL
POP DS ; *
JNE hacer_seek ; seek necesario
CMP AH,40h ; ¿error de seek previo?
JNE seek_ok ; no, evitar seek innecesario
hacer_seek: MOV AL,0Fh
CALL fdc_write ; comando 'seek'
JC fallo_seek
MOV AL,cabezal
SHL AL,2
OR AL,unidad
CALL fdc_write ; enviar HD, US1, US0
MOV AL,cilindro
CALL fdc_write ; enviar cilindro
CALL espera_int ; esperar interrupción
JC fallo_seek
MOV AL,8
CALL fdc_write ; comando 'leer estado int...'
JC fallo_seek
CALL fdc_read ; leer registro de estado 0
JC fallo_seek
MOV AH,AL
CALL fdc_read ; leer cilindro actual
TEST AH,11000000b ; comprobar ST0
JNZ fallo_seek
MOV AL,15 ; estabilización para escritura
CMP orden,F_WRITE
JE rseek_ok
MOV AL,1 ; estabilización para lectura
rseek_ok: CBW ; AH = 0
CALL retardo ; esperar asentamiento cabezal
seek_ok: POPA
CLC ; retornar con éxito
RET
fallo_seek: POPA
STC ; retornar indicando fallo
RET
seek_drv ENDP
; ------------ Establecer velocidad de transferencia correcta si aún
; no ha sido seleccionada y borrar el resultado de otra
; operación previa.
set_rate PROC
PUSHA
CALL pista0?
MOV AX,[SI].vunidad ; velocidad pista 0 / demás
JZ vel_ok
MOV AL,AH
vel_ok: PUSH DS ; *
PUSH 40h
POP DS
MOV AH,DS:[8Bh]
SHR AH,6 ; aislar bits de velocidad
CMP AL,AH
JE vel_set ; velocidad ya seleccionada
MOV DX,3F7h
OUT DX,AL ; seleccionarla
SHL AL,6
AND BYTE PTR DS:[8Bh],00111111b
OR DS:[8Bh],AL
vel_set: POP DS ; *
LEA DI,status
MOV CX,8
borra_status: MOV [DI],CH ; borrar información de estado
INC DI
LOOP borra_status
POPA
RET
set_rate ENDP
; ------------ Recalibrar la unidad (si hay error se intenta otra vez
; para el caso de que deba moverse más de 77 pistas).
recalibrar PROC
PUSHA
MOV BX,94h
ADD BL,unidad
PUSH DS ; *
PUSH 40h
POP DS
MOV [BX],BH ; pista actual = 0
POP DS ; *
MOV CX,2 ; dos veces como mucho
recalibra: MOV AL,7
CALL fdc_write ; comando de 'recalibrado'
JC fallo_recal
MOV AL,cabezal
SHL AL,2
OR AL,unidad
CALL fdc_write ; enviar HD, US1, US0
JC fallo_recal
CALL espera_int ; esperar interrupción
JC fallo_recal
MOV AL,8
CALL fdc_write ; comando 'leer estado int...'
JC fallo_recal
CALL fdc_read ; leer registro de estado 0
JC fallo_recal
MOV AH,AL
CALL fdc_read ; leer cilindro actual
XOR AH,00100000b ; bajar bit de 'seek end'
TEST AH,11110000b ; comprobar resultado y ST0
JNZ fallo_recal ; sin 'seek end' o TRK0
MOV AX,1 ; pausa de 1 ms
CALL retardo
JMP recal_ret
fallo_recal: LOOP recalibra ; reintentar comando
STC ; condición de fallo
recal_ret: POPA
RET
recalibrar ENDP
; ------------ Cargar o escribir sector(es) del disco en ES:DI,
; actualizando la dirección en ES:DI pero sin alterar
; ningún otro registro. Si hay error se devuelve CF=1 y
; no se modifica ES:DI. A partir de fdc_result se dejan
; los 7 bytes que devuelve el FDC al final del acceso.
; En caso de verificación (F_VERIFY) se programa el DMA
; para que no realice transferencia física (convenio de
; las BIOS con fecha 15/11/85 y posterior).
sector_io PROC
XPUSH <AX, BX, CX, DX>
MOV CL,tsector
MOV CH,0
STC
RCL CH,CL
MOV CL,0 ; nº de bytes por sector
MOV AL,sector_fin
SUB AL,sector_ini
INC AX
CBW ; AX sectores (AH = 0)
MUL CX
MOV DX,AX ; bytes totales
MOV CX,AX
DEC CX ; bytes totales - 1
MOV AX,ES
CALL calc_dir_DMA ; AX:DI -> base BX y página AH
JC sector_io_ko
MOV AL,orden ; modo DMA necesario
CALL prepara_DMA
CMP AL,F_WRITE
MOV AL,11000101b ; comando de escritura del FDC
JE orden_io_ok
MOV AL,11100110b ; comando leer (verif.) del FDC
orden_io_ok: CALL fdc_write ; comando leer/escribir del FDC
JC sector_io_ko
MOV AL,cabezal
SHL AL,2
OR AL,unidad
CALL fdc_write ; byte 1 de la orden
MOV AL,cilindro
CALL fdc_write ; enviar cilindro
MOV AL,cabezal
CALL fdc_write ; enviar cabezal
MOV AL,sector_ini
CALL fdc_write ; enviar nº sector
MOV AL,tsector
CALL fdc_write ; longitud sector
MOV AL,sector_fin
CALL fdc_write ; último sector
MOV AL,[SI].gap
CALL fdc_write ; GAP de lectura/escritura
MOV AL,128
CALL fdc_write ; tamaño sector si longitud=0
CALL espera_int
PUSHF ; *
LEA BX,fdc_result
MOV CX,7
sect_io_res: CALL fdc_read ; leyendo resultados
MOV [BX],AL
INC BX
LOOP sect_io_res
POPF ; *
JC sector_io_ko
TEST fdc_result,11000000b
JNZ sector_io_ko
ADD DI,DX ; actualizar dirección
CLC ; Ok
JMP sector_io_fin
sector_io_ko: STC ; indicar fallo
sector_io_fin: XPOP <DX, CX, BX, AX>
RET
sector_io ENDP
; ------------ Devolver en AH la página de DMA y en BX la base. A la
; entrada, AX:DI -> dirección de memoria y CX = bytes-1.
; Si se cruza una frontera de DMA se devuelve el error.
calc_dir_DMA PROC
PUSH DX
MOV BX,16
MUL BX
ADD AX,DI
ADC DX,0 ; DX:AX = dirección 20 bits
MOV BX,AX ; base en BX
MOV AH,DL ; página
MOV DX,CX
ADD DX,BX
JNC dir_DMA_ok
MOV status,9 ; error de frontera de DMA
dir_DMA_ok: POP DX
RET
calc_dir_DMA ENDP
; ------------ Esperar interrupción de disquete durante casi 2
; segundos antes de considerar que ha sido un fracaso.
espera_int PROC
STI
PUSHA
XPUSH <DS, 40h>
POP DS
MOV AX,9001h
CLC
INT 15h ; permitir multitarea
MOV DX,0280h
MOV BX,3Eh
JC timeout_int
esp_int_1s: XOR CX,CX
esp_int: TEST [BX],DL ; ¿llegó la interrupción?
JNZ fin_espera
PMICRO
LOOP esp_int ; esperar durante casi 1 seg.
DEC DH
JNZ esp_int_1s
timeout_int: OR CS:status,DL ; timeout
STC
fin_espera: PUSHF
AND BYTE PTR [BX],7Fh ; para la próxima vez
POPF
POP DS
POPA
RET
espera_int ENDP
; ------------ Preparar DMA para E/S. A la entrada, BX = dirección de
; base, AH = registro de página y CX = nº bytes - 1.
prepara_DMA PROC
PUSH AX
CLI
OUT 0Bh,AL ; registro de modo del DMA
MOV AL,0
DELAY
OUT 0Ch,AL ; clear first/last flip-flop
MOV AL,BL
DELAY
OUT 4,AL
MOV AL,BH
DELAY
OUT 4,AL ; enviada dirección base
DELAY
MOV AL,AH
OUT 81h,AL ; registro de página del DMA
MOV AL,CL
DELAY
OUT 5,AL
MOV AL,CH
DELAY
OUT 5,AL ; enviada cuenta de bytes
STI
MOV AL,2
DELAY
OUT 0Ah,AL ; habilitar canal 2 de DMA
POP AX
RET
prepara_DMA ENDP
; ------------ Recibir byte del FDC en AL. A la vuelta, CF=1 si
; la operación fracasó (el FDC no estaba listo) y
; se indica la condición de timeout en «status».
fdc_read PROC
XPUSH <CX, DX, AX>
CALL fdc_respiro ; no abrasar el FDC
MOV DX,3F4h ; registro de estado del FDC
MOV CX,133 ; constante para 0,002 segundos
espera_rd: DELAY
IN AL,DX
AND AL,11000000b
CMP AL,11000000b ; ¿dato listo?
JE fdc_rd_ok
DELAY
IN AL,61h
AND AL,10h
CMP AL,AH
JE espera_rd ; reintentarlo durante 15,09 µs
MOV AH,AL
LOOP espera_rd
XPOP <AX, DX, CX>
OR status,80h ; timeout
MOV AL,0
STC ; fallo
RET
fdc_rd_ok: POP AX
INC DX ; apuntar al registro de datos
DELAY
IN AL,DX ; leer byte del FDC
XPOP <DX, CX>
CLC ; Ok
RET
fdc_read ENDP
; ------------ Enviar byte AL al FDC. A la vuelta, CF=1 si
; la operación fracasó (el FDC no estaba listo) y
; se indica la condición de timeout en «status».
fdc_write PROC
XPUSH <CX, DX, AX>
CALL fdc_respiro ; no abrasar el FDC
MOV DX,3F4h ; registro de estado del FDC
MOV CX,133 ; constante para 0,002 segundos
espera_wr: DELAY
IN AL,DX
TEST AL,80h ; ¿listo para E/S?
JNZ fdc_wr_ok
DELAY
IN AL,61h
AND AL,10h
CMP AL,AH
JE espera_wr ; reintentarlo durante 15,09 µs
MOV AH,AL
LOOP espera_wr
XPOP <AX, DX, CX>
OR status,80h ; timeout
STC ; fallo
RET
fdc_wr_ok: INC DX ; apuntar al registro de datos
POP AX
DELAY
OUT DX,AL ; enviar byte al FDC
XPOP <DX, CX>
CLC ; Ok
RET
fdc_write ENDP
; ------------ Retardo de 60 µs para dar tiempo al FDC en 486 rápidos.
fdc_respiro PROC
XPUSH <AX, CX>
MOV CX,4
fdc_ret: PMICRO
LOOP fdc_ret
XPOP <CX, AX>
RET
fdc_respiro ENDP
; ------------ Esperar exactamente AX milisegundos.
retardo PROC
PUSHF
PUSHA
MOV DX,16970 ; 16970 = 1193180/18*256/1000
MUL DX
MOV CL,AH ; dividir DX:AX entre 256 y
MOV CH,DL ; dejar el resultado en DX:CX
MOV DL,DH
MOV DH,0 ; DX:CX 15,09 µs-avos
retardando: PMICRO
LOOP retardando
AND DX,DX
JZ retardado
DEC DX
JMP retardando
retardado: POPA
POPF
RET
retardo ENDP
; ------------ Esta subrutina sustituye a la macro PMICRO del programa
; completo por razones de espacio.
pmicro_iter: DELAY ; retardo de aprox. 15,09 µs
IN AL,61h ; (exactamente 18/1193180 sg.)
AND AL,10h ; La rutina se puede ejecutar
CMP AL,AH ; repetitivamente (se apoya en
JE pmicro_iter ; AX) para hacer retardos a
MOV AH,AL ; través de la temporización
RET ; del refresco de la memoria
; ------------ Código invocado durante el SuperBOOT desde 2MFKIT.ASM
; A la entrada: CS=ES, SS=0 y AX = tipo unidades.
initcode: PUSH DS
PUSH SS
POP DS
MOV ES:[info_A.tipo_drv],AL ; anotar tipo de A:
MOV ES:[info_B.tipo_drv],AH ; anotar tipo de B:
LEA DI,ant_int13
MOV SI,13h*4 ; vector de INT 13h
CLD
CLI
MOVSW
MOVSW ; anotada dirección INT 13h
MOV WORD PTR [SI-4],OFFSET ges_int13
MOV [SI-2],ES
STI ; desviada INT 13h
POP DS
RETF ; volver a 2MFKIT
DB 5 DUP (0) ; para completar 2560 bytes exactos
ant_int13 LABEL DWORD ; vector de la INT 13h previa
ant_int13_off DW initcode
ant_int13_seg DW 0AA55h ; significa "2MFBOOT correcto"
; --- Ubicación del sector de hasta 2048 bytes.
; Por su peculiar ubicación en la memoria (al final
; de los 640K, 512K, etc, pero sin llegar) nunca
; cruzará una frontera de DMA...
buffer_io EQU $ ; obviamente ¡no se almacena!
ON EQU 1 ; constantes booleanas
OFF EQU 0
F_READ EQU 46h ; modo DMA para lectura
F_WRITE EQU 4Ah ; modo DMA para escritura
F_VERIFY EQU 42h ; modo DMA para verificación
_PRINCIPAL ENDS
END